NAT Gateway のコストが気になるので CloudWatch ダッシュボードと仲良くなってみた
どの NAT Gateway で料金がかかっているんだろう
コンバンハ、千葉(幸)です。
NAT Gateway の料金が気になる機会がありました。環境には多くの NAT Gateway が存在するため、まずはどの NAT Gateway でコストがかかっているのか確認したいと考えました。
デフォルトで用意されている CloudWatch ダッシュボードを覗いてみると多くのメトリクスが表示されます。
▲ メトリクスの種類が多いですね
パッと眺めてみたときに、似たようなメトリクス名が並んでいて混乱してしまいました。
- BytesInFromDestination
- BytesInFromSource
- BytesOutToDestination
- BytesOutToSource
- PacketsInFromDestination
- PacketsInFromSource
- PacketsOutToDestination
- PacketsOutToSource
30 分くらい眺めていたら意味が分かってきたので、理解した内容を記しておきます。
このエントリで書くこと
- NAT Gateway のメトリクスの考え方
- NAT Gateway ダッシュボードの見方
- 特定の NAT Gateway を宛先にもつルートテーブルの確認の仕方
NAT Gateway についておさらい
メトリクスを確認する前に NAT Gateway の基本的な部分についておさらいしておきましょう。
NAT Gateway は VPC 内のクライアントに対して NAT デバイスとして機能します。より具体的に言うと NAPT を行ってくれます。IP アドレスだけでなくポートも変換してくれるため、1対多の変換に対応しています。
プライベートサブネット上のクライアントに対してインターネットへのアウトバウンド通信の経路を確保する用途で用いられることが多いため誤解されやすいですが、プライベート IP アドレスとグローバル IP アドレスの変換を行うのは NAT Gateway の役割ではありません。
NAT Gateway はあくまで自身が持つプライベート IP アドレスと変換するだけで、「NAT Gateway のプライベート IP アドレスと NAT Gateway のグローバル IP アドレス」を変換するのはインターネットゲートウェイの役割です。
インターネット上ではなくオンプレミスを宛先とするケースを想定し、プライベートタイプの NAT Gateway を構成することも可能です。パブリックタイプであってもプライベートタイプであっても、通信方向は片方向のみです。(クライアントから宛先への方向の通信の開始のみ NAT Gateway は受け付ける。もちろん戻りの通信は正常に処理される。)
その他の仕様として以下が挙げられます。
- サポートしているプロトコルは TCP、UDP、ICMP
- IPv4 または IPv6 トラフィックをサポート
- IPv6 トラフィックの場合 NAT64 を実行
- 5Gbps の帯域幅をサポートし、自動的に 100 Gbps までスケールアップ
- 100万パケット/秒をサポートし、自動的に 1,000万パケット/秒までスケールアップ
- 一意の宛先ごとに 55,000 の同時接続をサポート
- 使用するエフェメラルポートは 1024~65535
詳細は以下を参照してください。
NAT Gateway のデータ処理に関する課金
NAT Gateway は配置しているだけで1時間ごとに 0.062 USD の料金が発生します。(2022/12現在、東京リージョンの場合。以降も同様。)
さらに、データ処理量 1GB ごとに 0.062 USD の料金も発生します。ここでのデータ処理量は行きの通信・戻りの通信の双方を含みます。
このデータ処理量による料金が嵩んでいる場合、なるべく NAT Gateway を経由させない構成を取れないか検討するのがよいでしょう。いくつかのパターンが以下エントリで取り上げられています。
明確なアンチパターンは「S3 向けの通信を NAT Gateway を経由している」です。S3 向けの通信はゲートウェイ型の VPC エンドポイントを経由することで追加の料金なしで実現できます。
サブネットルートテーブルに追加のエントリが必要になる、というインパクトはありますが、料金の観点のほか「VPC エンドポイントポリシーによるアクセス先の制御」も可能となるため、採用することで大きなメリットが期待できます。
NAT Gateway のメトリクス一覧を確認する
NAT Gateway に関する CloudWatch メトリクスは以下ページにまとまっています。
勝手に番号を振ってまとめた表が以下です。
# | メトリクス | 単位 | 有用な統計 | 説明 | 対のメトリクス |
---|---|---|---|---|---|
1 | ActiveConnectionCount | カウント | Max | NAT ゲートウェイを介した同時アクティブ TCP 接続の総数 | - |
2 | BytesInFromDestination | バイト | Sum | NAT ゲートウェイが宛先から受信したバイト数 | #5 |
3 | BytesInFromSource | バイト | Sum | VPC 内のクライアントから NAT ゲートウェイが受信したバイト数 | #4 |
4 | BytesOutToDestination | バイト | Sum | NAT ゲートウェイ経由で宛先に送信されたバイト数 | #3 |
5 | BytesOutToSource | バイト | Sum | NAT ゲートウェイ経由で VPC 内のクライアントに送信されたバイト数 | #2 |
6 | ConnectionAttemptCount | カウント | Sum | NAT ゲートウェイ経由で試行された接続の回数 | #7 |
7 | ConnectionEstablishedCount | カウント | Sum | NAT ゲートウェイ経由で確立された接続の数 | #6 |
8 | ErrorPortAllocation | カウント | Sum | NAT ゲートウェイが送信元ポートを割り当てられなかった回数 | - |
9 | IdleTimeoutCount | カウント | Sum | アクティブ状態からアイドル状態に遷移した接続の数 | - |
10 | PacketsDropCount | カウント | Sum | NAT ゲートウェイによってドロップされたパケットの数 | - |
11 | PacketsInFromDestination | カウント | Sum | NAT ゲートウェイが宛先から受信したパケットの数 | #14 |
12 | PacketsInFromSource | カウント | Sum | VPC 内のクライアントから NAT ゲートウェイが受信したパケットの数 | #13 |
13 | PacketsOutToDestination | カウント | Sum | NAT ゲートウェイ経由で宛先に送信されたパケットの数 | #12 |
14 | PacketsOutToSource | カウント | Sum | NAT ゲートウェイ経由で VPC 内のクライアントに送信されたパケットの数 | #11 |
いくつかのメトリクスは他のメトリクスと比較することでより意味を持つようになります。それを「対のメトリクス」として表現しています。
InFrom と OutTo と Source と Destination
全 14 個のメトリクスのうち 8 個がこれに関するメトリクスです。#2~5,11~14 が該当します。
冒頭で「似たようなメトリクスが並んでいて混乱する」と挙げたのもこれらです。絵を描いたら簡単に理解できました。
ここでは以下前提のもと図示していますが、他の構成でも考え方は同じです。
- NAT Gateway がパブリックタイプ
- 宛先がインターネット上のリソース
- 送信元(クライアント)が EC2 インスタンス
行きの通信、戻りの通信ごとに対となる組み合わせがあります。
- 行きの通信:
InFromSource
,OutToDestination
- 戻りの通信:
InFromDestination
,OutToSource
これらは組み合わせごとに同じ値となるのが基本ですが、NAT Gateway の処理によってデータがロストする・ブロックされるといったことがある場合には差異が生じることになります。
Bytes と Packets
#2~5は Bytes 、#11~14は Packets のメトリクスとなっています。どちらのメトリクスでも傾向としては同じになるはずのため、好きなほうを選択してよいかと思います。
パッと「1パケットって何バイトくらいになるんだっけ?」というのが出てこなかったので調べ直しました。
調べ直したものの細かい部分の数字が自信がないのですが、おおよそ 50 ~ 1500バイトの中におさまるはずです。わたしの環境ではアウトバウンドでは 100 ~ 200 程度、インバウンドでは 1,000 程度がボリュームゾーンでした。
その他のメトリクス
#1. ActiveConnectionCount
アクティブな接続数に関するメトリクスです。TCP 接続に限定されることに注意してください。
#6. ConnectionAttemptCount と #7. ConnectionEstablishedCount
前者が試行の回数、後者が確立された回数です。後者の方が数が少ない場合、接続が成功していない試行があることを表します。
8. ErrorPortAllocation
0 より大きい場合、NAT Gateway が送信元ポートを割り当てられなかった接続があることを表します。先述の通り「一意の宛先ごとに同時接続数 55,000」がサポートされているため、このエラーが発生することは稀かと思います。
NAT ゲートウェイは送信先別に最大 55,000 の同時接続をサポートできます。この制限は、単一の送信先に 1 秒あたり約 900 の接続 (1 分あたり約 55,000 の接続) を作成する場合にも適用されます。送信先 IP アドレス、送信先ポート、またはプロトコル (TCP/UDP/ICMP) が変更された場合は、追加の 55,000 の接続を作成できます。55,000 を超える接続の場合は、ポートの割り当てエラーによる接続エラーの可能性が高くなります。これらのエラーは、NAT ゲートウェイの
ErrorPortAllocation
CloudWatch メトリクスを表示することでモニタリングできます。
9. IdleTimeoutCount
アクティブ状態からアイドル状態に遷移した接続の数を表します。以下を満たした場合アイドル状態に遷移するとのことです。
- アクティブな接続が正常に閉じられなかった
- 350 秒アクティビティがなかった
10. PacketsDropCount
NAT Gateway の一時的な問題によりパケットがドロップされた場合にこのメトリクスが記録されます。トータルのトラフィックに対してこの値が 0.01 % を超える場合、サービスヘルスダッシュボードを確認すること、とのことです。
(逆説的に考えると、その程度を閾値にサービスヘルスダッシュボードで障害として記録されるものと推察できます。)
NAT Gateway の CloudWatch ダッシュボードを覗いてみる
メトリクスの意味が理解できたところで、改めて NAT Gateway の CloudWatch ダッシュボードを覗いてみます。
特に設定をしていなくても、自動でダッシュボードを用意してくれています。CloudWatch コンソールから、「ダッシュボード」→「自動ダッシュボード」→「VPC NAT Gateways」に遷移します。
改めて確認することで、以下の傾向が確認できました。
- 特定の NAT Gateway で多くのデータ処理が発生している
- アップロードよりダウンロードの比重が大きい
特定の NAT Gateway 向けのルートを持つルートテーブルを確認する
データ処理量が多い NAT Gateway が特定できたので、その NAT Gateway を使用しているクライアントにあたりをつけたいです。環境には多くの VPC 、サブネット、ルートテーブルが存在していたため、コンソールからの確認が難しく、以下の AWS CLI コマンドを用いました。
$ aws ec2 describe-route-tables\ --filters "Name=route.nat-gateway-id,Values=nat-xxxxxxx"\ | jq -c '.RouteTables | sort_by(.Tags[] | select(.Key == "Name").Value) | .[] | [(.Tags[] | select(.Key == "Name").Value),.RouteTableId,.VpcId,.Associations[].SubnetId]' ["RouteTable1","rtb-xxxxxxxxxx","vpc-yyyyyyyyyy","subnet-zzzzzzzzzzz"] ["RouteTable2","rtb-xxxxxxxxxx","vpc-yyyyyyyyyy","subnet-zzzzzzzzzzz","subnet-aaaaaaaaaa"] ...
--filters
で NAT Gateway ID を指定してフィルタリング指定しています。これは以下エントリの内容を踏襲しています。
--filters "Name=route.nat-gateway-id,Values=nat-xxxxxxx","nat-yyyyyyy"
のように NAT Gateway を複数指定すれば OR 条件でフィルタリングできます。
また、以下のように指定すれば、「特定の NAT Gatewey 宛のルートをもち、かつ S3 VPC エンドポイント宛のルートを持つ」という AND 条件のフィルタリングが可能です。
$ aws ec2 describe-route-tables\ --filters "Name=route.nat-gateway-id,Values=nat-xxxxxxx,nat-yyyyyyy"\ "Name=route.destination-prefix-list-id,Values=pl-61a54008"\ | jq '.RouteTables[].RouteTableId' | sort # 任意の処理
(pl-61a54008
は東京リージョンの S3 のプレフィックスリストを表します。)
"Name=route.destination-prefix-list-id,Values=pl-61a54008"
を条件に加えた時とそうでない時とで結果に差異が出る場合、「NAT Gateway 向けのルートを持つが S3 用のゲートウェイエンドポイント向けのルートを持たない」ルートテーブルがあるということになるので、重点的に確認をするとよいでしょう。
ひとまずここまでで特定の NAT Gateway を経由するクライアントが存在するサブネットまで絞り込みができました。
終わりに
NAT Gateway のメトリクスに関する CloudWatch ダッシュボードと仲良くなりたい、というエントリでした。
いろいろ話が発散してしまいましたが、一番書きたかったのは以下のメトリクスの違いです。
- BytesInFromDestination
- BytesInFromSource
- BytesOutToDestination
- BytesOutToSource
- PacketsInFromDestination
- PacketsInFromSource
- PacketsOutToDestination
- PacketsOutToSource
Source とか Destionation の考え方は以下の通りで、
1 パケットあたりおよそ 50 ~1500 バイトである、という点を押さえてもらえれば大丈夫です。
何らか参考になれば幸いです。
以上、 チバユキ (@batchicchi) がお送りしました。